/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.web;

import com.google.inject.Inject;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.validation.Validate;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.xptracker.domain.SavedQuery;
import org.xptracker.domain.Story;
import org.xptracker.domain.User;
import org.xptracker.domain.WikiPage;
import org.xptracker.persistence.PersistenceManager;
import org.xptracker.search.Searcher;

import java.io.StringReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@UrlBinding("/Search.action")
public class SearchActionBean extends StandardActionBean {
  private static final int PAGE_SIZE = 15;

  private String queryId;

  private String query;
  private String saveAs;
  private List<Story> searchResults;
  private List<WikiPage> wikiSearchResults;
  private boolean searched = false;
  private String sortBy;
  private boolean sortDesc;

  @Inject
  private Searcher searcher;

  @Validate(required = true)
  public String getQuery() {
    return query;
  }

  public void setQuery(String query) {
    this.query = query;
  }

  public List<Story> getSearchResults() {
    return searchResults;
  }

  public void setSearchResults(List<Story> searchResults) {
    this.searchResults = searchResults;
  }

  public List<WikiPage> getWikiSearchResults() {
    return wikiSearchResults;
  }

  public void setWikiSearchResults(List<WikiPage> wikiSearchResults) {
    this.wikiSearchResults = wikiSearchResults;
  }

  public boolean isSearched() {
    return searched;
  }

  public void setSearched(boolean searched) {
    this.searched = searched;
  }

  public String getSaveAs() {
    return saveAs;
  }

  public void setSaveAs(String saveAs) {
    this.saveAs = saveAs;
  }

  public String getQueryId() {
    return queryId;
  }

  public void setQueryId(String queryId) {
    this.queryId = queryId;
  }

  public int getPageSize() {
    return searchResults.size() > PAGE_SIZE ? PAGE_SIZE : 0;
  }

  public String getSortBy() {
    return sortBy;
  }

  public void setSortBy(String sortBy) {
    this.sortBy = sortBy;
  }

  public boolean isSortDesc() {
    return sortDesc;
  }

  public void setSortDesc(boolean sortDesc) {
    this.sortDesc = sortDesc;
  }

  @DefaultHandler
  public Resolution search() {
    WikiActionBean.getHistory(getContext().getRequest().getSession()).clear();

    searched = true;
    searchResults = searcher.search(Story.class, query);
    wikiSearchResults = searcher.search(WikiPage.class, query);

    if (StringUtils.isNotBlank(saveAs)) {
      persistenceManager.inTransaction(new PersistenceManager.UpdateHandler<Boolean>() {
        public Boolean doUpdate(PersistenceManager.UpdateReceiver receiver) {
          User user = getCurrentUser();
          if (user.hasQuery(saveAs)) { // Simulating cascade=save-update
            receiver.remove(user.removeQuery(saveAs));
          }
          receiver.insert(user.addQuery(saveAs, query));
          receiver.update(user);
          getContext().getMessages().add(new SimpleMessage("Query saved as ''" + saveAs + "''"));
          return null; 
        }
      });
    }

    if (wikiSearchResults.isEmpty() && searchResults.size() == 1) {
      return new RedirectResolution(DisplayActionBean.class).addParameter("id", searchResults.get(0).getExtId());
    } else if (searchResults.isEmpty() && wikiSearchResults.size() == 1) {
      return new RedirectResolution(WikiActionBean.class).addParameter("name", wikiSearchResults.get(0).getName());
    } else if (StringUtils.isNotEmpty(sortBy) && !"relevance".equals(sortBy) && !searchResults.isEmpty()) {
      Comparator<Story> comparator = new Comparator<Story>() {
        public int compare(Story s1, Story s2) {
          try {
            Comparable value1 = (Comparable) PropertyUtils.getProperty(s1, sortBy);
            Comparable value2 = (Comparable) PropertyUtils.getProperty(s2, sortBy);

            return (value1 == null ? (value2 == null ? 0 : -1) : (value2 == null ? 1 : value1.compareTo(value2)));
          } catch (Exception e) {
            throw new RuntimeException(e);
          }
        }
      };

      if (sortDesc) {
        comparator = Collections.reverseOrder(comparator);
      }
      Collections.sort(searchResults, comparator);
    }
    return new ForwardResolution("searchResults.jsp");
  }

  @HandlesEvent("LoadQuery")
  @DontValidate
  public Resolution loadQuery() {
    SavedQuery query = domain.loadEntity(SavedQuery.class, queryId);
    String result = "* query not found *";
    if (query != null) {
      result = query.getQuery();
    }
    return new StreamingResolution("text", new StringReader(result));
  }
}
